﻿using AutoMapper;
using CodeSpirit.Core;
using CodeSpirit.Core.Constants;
using CodeSpirit.Core.IdGenerator;
using CodeSpirit.IdentityApi.Data.Models;
using CodeSpirit.IdentityApi.Dtos.Role;
using CodeSpirit.Shared.Repositories;
using CodeSpirit.Shared.Services;
using CodeSpirit.Shared.Dtos.Common;
using LinqKit;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Distributed;
using System.Data;
using System.Text.Json;
using CodeSpirit.Authorization.Extensions;

namespace CodeSpirit.IdentityApi.Services
{
    public class RoleService : BaseCRUDIService<ApplicationRole, RoleDto, long, RoleCreateDto, RoleUpdateDto, RoleBatchImportItemDto>, IRoleService
    {
        private readonly IRepository<ApplicationRole> _roleRepository;
        private readonly IDistributedCache _cache;
        private readonly ILogger<RoleService> _logger;
        private readonly IIdGenerator idGenerator;
        private readonly IRepository<ApplicationUser> _userRepository;

        public RoleService(
            IRepository<ApplicationRole> roleRepository,
            IMapper mapper,
            IDistributedCache cache,
            ILogger<RoleService> logger,
            IIdGenerator idGenerator,
            IRepository<ApplicationUser> userRepository,
            EnhancedBatchImportHelper<RoleBatchImportItemDto> importHelper)
            : base(roleRepository, mapper, importHelper)
        {
            _roleRepository = roleRepository;
            _cache = cache;
            _logger = logger;
            this.idGenerator = idGenerator;
            _userRepository = userRepository;
        }

        public async Task<PageList<RoleDto>> GetRolesAsync(RoleQueryDto queryDto)
        {
            ExpressionStarter<ApplicationRole> predicate = PredicateBuilder.New<ApplicationRole>(true);

            if (!string.IsNullOrEmpty(queryDto.Keywords))
            {
                predicate = predicate.Or(x => x.Name.Contains(queryDto.Keywords));
                predicate = predicate.Or(x => x.Description.Contains(queryDto.Keywords));
            }

            return await GetPagedListAsync(
                queryDto,
                predicate,
                "RolePermission"
            );
        }

        public async Task<PageList<RoleDto>> GetSystemRolesAsync(RoleQueryDto queryDto)
        {
            ExpressionStarter<ApplicationRole> predicate = PredicateBuilder.New<ApplicationRole>(true);

            // 限制查询条件为系统租户
            predicate = predicate.And(x => x.TenantId == TenantConstants.SystemTenantId);

            if (!string.IsNullOrEmpty(queryDto.Keywords))
            {
                predicate = predicate.Or(x => x.Name.Contains(queryDto.Keywords));
                predicate = predicate.Or(x => x.Description.Contains(queryDto.Keywords));
            }

            // 使用忽略多租户过滤器的查询方式
            var query = _roleRepository.CreateQuery()
                .IgnoreQueryFilters() // 忽略多租户过滤器
                .Include(r => r.RolePermission)
                .Where(predicate);

            var totalCount = await query.CountAsync();
            var items = await query
                .Skip((queryDto.Page - 1) * queryDto.PerPage)
                .Take(queryDto.PerPage)
                .ToListAsync();

            var mappedItems = Mapper.Map<List<RoleDto>>(items);

            return new PageList<RoleDto>
            {
                Total = totalCount,
                Items = mappedItems
            };
        }

        public async Task<RoleDto> CreateSystemRoleAsync(RoleCreateDto createDto)
        {
            // 检查系统租户下是否已存在同名角色
            var existingRole = await _roleRepository.CreateQuery()
                .IgnoreQueryFilters()
                .FirstOrDefaultAsync(r => r.Name == createDto.Name && r.TenantId == TenantConstants.SystemTenantId);

            if (existingRole != null)
            {
                throw new AppServiceException(400, "系统角色名称已存在！");
            }

            ApplicationRole role = Mapper.Map<ApplicationRole>(createDto);
            role.TenantId = TenantConstants.SystemTenantId; // 确保在系统租户下创建
            role.NormalizedName = role.Name.ToUpperInvariant();
            role.Id = idGenerator.NewId();

            if (createDto.PermissionAssignments != null && createDto.PermissionAssignments.Any())
            {
                // 优化权限ID数组，移除冗余的父级权限
                var optimizedPermissionIds = OptimizePermissionIds(createDto.PermissionAssignments.Distinct().ToArray());
                
                role.RolePermission = new RolePermission
                {
                    RoleId = role.Id,
                    TenantId = TenantConstants.SystemTenantId,
                    PermissionIds = optimizedPermissionIds
                };
            }

            // 使用 DbContext 直接添加，绕过多租户过滤器
            ApplicationRole createdEntity = await Repository.AddAsync(role);
            return Mapper.Map<RoleDto>(createdEntity);
        }

        public async Task<(int successCount, List<string> failedIds)> BatchImportRolesAsync(List<RoleBatchImportItemDto> importDtos)
        {
            // 去重处理
            List<RoleBatchImportItemDto> distinctImportDtos = importDtos
                .GroupBy(x => x.Name.ToLower())
                .Select(g => g.First())
                .ToList();

            (int successCount, List<string> failedIds) result = await BatchImportAsync(distinctImportDtos);
            return result;
        }

        /// <summary>
        /// 获取用户权限列表
        /// </summary>
        /// <param name="userId">用户ID</param>
        /// <returns>用户权限列表</returns>
        public async Task<HashSet<string>> GetUserPermissionsAsync(long userId)
        {
            // 获取用户信息以确定租户ID
            var user = await _userRepository.CreateQuery()
                .IgnoreQueryFilters()
                .FirstOrDefaultAsync(u => u.Id == userId);
                
            if (user == null)
            {
                _logger.LogWarning("获取权限失败，用户不存在，用户ID: {UserId}", userId);
                return new HashSet<string>();
            }
            
            // 定义缓存键（包含租户信息）
            string cacheKey = CacheKeys.GetUserPermissionsCacheKey(userId, user.TenantId);
            
            // 尝试从缓存中获取
            var cachedPermissions = await _cache.GetAsync<HashSet<string>>(cacheKey);
            if (cachedPermissions != null)
            {
                _logger.LogDebug("从缓存中获取用户权限，用户ID: {UserId}", userId);
                return cachedPermissions;
            }
            
            // 缓存未命中，从数据库获取详细信息
            user = await _userRepository.CreateQuery()
                .IgnoreQueryFilters()
                .Include(u => u.UserRoles)
                    .ThenInclude(ur => ur.Role)
                        .ThenInclude(r => r.RolePermission)
                .FirstOrDefaultAsync(u => u.Id == userId);
            
            // 收集用户所有角色的所有权限
            var permissions = new HashSet<string>();
            foreach (var userRole in user.UserRoles)
            {
                if (userRole.Role?.RolePermission?.PermissionIds != null)
                {
                    foreach (var permission in userRole.Role.RolePermission.PermissionIds)
                    {
                        permissions.Add(permission);
                    }
                }
            }
            
            // 将权限存入缓存
            var cacheOptions = new DistributedCacheEntryOptions
            {
                AbsoluteExpirationRelativeToNow = CacheKeys.UserPermissionsAbsoluteExpiration,
                SlidingExpiration = CacheKeys.UserPermissionsSlidingExpiration
            };
            
            await _cache.SetAsync(cacheKey, permissions, cacheOptions);
            _logger.LogDebug("已缓存用户权限，用户ID: {UserId}, 权限数量: {PermissionCount}", userId, permissions.Count);
            
            return permissions;
        }

        #region Override Base Methods

        public override async Task<RoleDto> CreateAsync(RoleCreateDto createDto)
        {
            if (await _roleRepository.ExistsAsync(r => r.Name == createDto.Name))
            {
                throw new AppServiceException(400, "角色名称已存在！");
            }

            ApplicationRole role = Mapper.Map<ApplicationRole>(createDto);
            role.NormalizedName = role.Name.ToUpperInvariant();

            // Generate a new ID for the role
            role.Id = idGenerator.NewId();
            
            if (createDto.PermissionAssignments != null && createDto.PermissionAssignments.Any())
            {
                // 优化权限ID数组，移除冗余的父级权限
                var optimizedPermissionIds = OptimizePermissionIds(createDto.PermissionAssignments.Distinct().ToArray());
                
                role.RolePermission = new RolePermission
                {
                    RoleId = role.Id,
                    PermissionIds = optimizedPermissionIds
                };
            }

            ApplicationRole createdEntity = await Repository.AddAsync(role);
            return Mapper.Map<RoleDto>(createdEntity);
        }

        protected override async Task OnUpdating(ApplicationRole entity, RoleUpdateDto updateDto)
        {
            // 如果名称发生变化，需要更新 NormalizedName
            if (!string.Equals(entity.Name, updateDto.Name, StringComparison.Ordinal))
            {
                entity.NormalizedName = updateDto.Name.ToUpperInvariant();
            }

            if (updateDto.PermissionIds != null)
            {
                string[] distinctPermissionIds = updateDto.PermissionIds.Distinct().ToArray();

                if (distinctPermissionIds.Any())
                {
                    // 优化权限ID数组，移除冗余的父级权限
                    var optimizedPermissionIds = OptimizePermissionIds(distinctPermissionIds);
                    
                    // Load the existing RolePermission if not already loaded
                    if (entity.RolePermission == null)
                    {
                        entity.RolePermission = await Repository.CreateQuery()
                            .Where(r => r.Id == entity.Id)
                            .Select(r => r.RolePermission)
                            .FirstOrDefaultAsync();
                    }

                    if (entity.RolePermission == null)
                    {
                        entity.RolePermission = new RolePermission
                        {
                            RoleId = entity.Id,
                            PermissionIds = optimizedPermissionIds
                        };
                    }
                    else
                    {
                        entity.RolePermission.PermissionIds = optimizedPermissionIds;
                    }
                }
                else
                {
                    // If no permission IDs are provided, remove the role permission
                    if (entity.RolePermission != null)
                    {
                        entity.RolePermission.PermissionIds = Array.Empty<string>();
                    }
                }
                
                // 角色权限变更，需要清除相关用户的权限缓存
                await InvalidateUserPermissionCachesAsync(entity.Id);
            }

            await base.OnUpdating(entity, updateDto);
        }

        /// <summary>
        /// 当角色权限变更时，清除所有关联用户的权限缓存
        /// </summary>
        private async Task InvalidateUserPermissionCachesAsync(long roleId)
        {
            try
            {
                // 查找拥有此角色的所有用户
                var userIds = await _userRepository.CreateQuery()
                    .Where(u => u.UserRoles.Any(ur => ur.RoleId == roleId))
                    .Select(u => u.Id)
                    .ToListAsync();

                foreach (var userId in userIds)
                {
                    // 获取用户租户信息以生成正确的缓存键
                    var user = await _userRepository.CreateQuery()
                        .IgnoreQueryFilters()
                        .FirstOrDefaultAsync(u => u.Id == userId);
                        
                    if (user != null)
                    {
                        string cacheKey = CacheKeys.GetUserPermissionsCacheKey(userId, user.TenantId);
                        await _cache.RemoveAsync(cacheKey);
                        _logger.LogDebug("已清除用户权限缓存，用户ID: {UserId}, 租户ID: {TenantId}, 角色ID: {RoleId}", userId, user.TenantId, roleId);
                    }
                    else
                    {
                        _logger.LogWarning("无法清除用户权限缓存，用户不存在，用户ID: {UserId}, 角色ID: {RoleId}", userId, roleId);
                    }
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "清除用户权限缓存失败，角色ID: {RoleId}", roleId);
            }
        }

        protected override async Task<IEnumerable<RoleBatchImportItemDto>> ValidateImportItems(IEnumerable<RoleBatchImportItemDto> importData)
        {
            // 去重处理：确保每个角色名唯一（在导入时去重）
            List<RoleBatchImportItemDto> distinctDtos = importData
                .GroupBy(dto => NormalizeRoleName(dto.Name))  // 使用标准化名称进行分组
                .Select(group => group.First())
                .ToList();

            // 检查数据库中是否已有重复的角色名
            List<string> normalizedRoleNames = distinctDtos.Select(dto => NormalizeRoleName(dto.Name)).ToList();
            List<ApplicationRole> existingRoles = await _roleRepository.CreateQuery()
                .Where(role => normalizedRoleNames.Contains(role.NormalizedName))  // 使用 NormalizedName 进行查询
                .ToListAsync();

            List<RoleBatchImportItemDto> duplicateRoles = distinctDtos
                .Where(dto => existingRoles.Any(role =>
                    role.NormalizedName == NormalizeRoleName(dto.Name)))
                .ToList();

            return duplicateRoles.Any()
                ? throw new AppServiceException(400, $"以下角色名已存在: {string.Join(", ", duplicateRoles.Select(dto => dto.Name))}！")
                : distinctDtos;
        }

        protected override async Task<ApplicationRole> GetEntityForUpdate(long id, RoleUpdateDto updateDto)
        {
            ApplicationRole entity = await _roleRepository.GetByIdAsync(id);
            return entity == null ? throw new AppServiceException(404, "角色不存在！") : entity;
        }

        protected override string GetImportItemId(RoleBatchImportItemDto importDto)
        {
            return importDto.Name;
        }

        protected override Task OnDeleting(ApplicationRole entity)
        {
            return entity.Name.Equals("Admin", StringComparison.OrdinalIgnoreCase)
                ? throw new AppServiceException(400, "Admin角色不允许删除！")
                : entity.RolePermission?.PermissionIds != null ? throw new AppServiceException(400, "请移除权限后再删除该角色！") : Task.CompletedTask;
        }

        protected override Task OnImportMapping(ApplicationRole entity, RoleBatchImportItemDto importDto)
        {
            base.OnImportMapping(entity, importDto);
            
            // 确保设置 NormalizedName
            entity.NormalizedName = entity.Name.ToUpperInvariant();
            return Task.CompletedTask;
        }

        // 建议添加一个帮助方法来统一处理角色名称的标准化
        private string NormalizeRoleName(string roleName)
        {
            return roleName?.ToUpperInvariant();
        }

        /// <summary>
        /// 优化权限ID数组，移除被通配权限覆盖的具体权限
        /// </summary>
        /// <param name="permissionIds">原始权限ID数组</param>
        /// <returns>优化后的权限ID数组</returns>
        private string[] OptimizePermissionIds(string[] permissionIds)
        {
            if (permissionIds == null || !permissionIds.Any())
            {
                return permissionIds;
            }

            var optimizedPermissions = new HashSet<string>(permissionIds, StringComparer.OrdinalIgnoreCase);
            var permissionsToRemove = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

            // 新的优化逻辑：
            // 1. 找出所有通配权限（以 _* 结尾）
            // 2. 移除被通配权限覆盖的具体权限
            // 示例：如果有 identity_*，则移除所有 identity_ 开头的具体权限

            foreach (var permission in permissionIds)
            {
                if (string.IsNullOrEmpty(permission)) continue;

                // 检查是否为通配权限（以 _* 结尾）
                if (permission.EndsWith("_*", StringComparison.OrdinalIgnoreCase))
                {
                    // 获取通配权限的前缀（移除 _*）
                    var prefix = permission.Substring(0, permission.Length - 2) + "_";
                    
                    _logger.LogDebug("发现通配权限: {Permission}，检查被覆盖的权限（前缀: {Prefix}）", permission, prefix);

                    // 找出所有被该通配权限覆盖的具体权限
                    foreach (var other in permissionIds)
                    {
                        if (string.IsNullOrEmpty(other) || other.Equals(permission, StringComparison.OrdinalIgnoreCase))
                            continue;

                        // 如果其他权限以该前缀开头，则被通配权限覆盖
                        if (other.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
                        {
                            permissionsToRemove.Add(other);
                            _logger.LogDebug("权限 {Permission} 被通配权限 {WildcardPermission} 覆盖，将被移除", 
                                other, permission);
                        }
                    }
                }
            }

            // 移除被通配权限覆盖的权限
            foreach (var permissionToRemove in permissionsToRemove)
            {
                optimizedPermissions.Remove(permissionToRemove);
            }

            var result = optimizedPermissions.ToArray();
            
            if (permissionsToRemove.Any())
            {
                _logger.LogInformation("权限优化完成，移除了 {RemovedCount} 个被通配权限覆盖的权限: [{RemovedPermissions}]", 
                    permissionsToRemove.Count, 
                    string.Join(", ", permissionsToRemove));
            }
            else
            {
                _logger.LogDebug("权限优化完成，没有需要移除的冗余权限");
            }

            return result;
        }

        #endregion
    }
}
